home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / lib / python2.4 / site-packages / psyco / profiler.py < prev    next >
Text File  |  2006-03-29  |  12KB  |  388 lines

  1. ###########################################################################
  2. #  Psyco profiler (Python part).
  3. #   Copyright (C) 2001-2002  Armin Rigo et.al.
  4.  
  5. """Psyco profiler (Python part).
  6.  
  7. The implementation of the non-time-critical parts of the profiler.
  8. See profile() and full() in core.py for the easy interface.
  9. """
  10. ###########################################################################
  11.  
  12. import _psyco
  13. from support import *
  14. import math, time, types, atexit
  15. try:
  16.     import thread
  17. except ImportError:
  18.     import dummy_thread as thread
  19.  
  20.  
  21. # current profiler instance
  22. current = None
  23.  
  24. # enabled profilers, in order of priority
  25. profilers = []
  26.  
  27. # logger module (when enabled by core.log())
  28. logger = None
  29.  
  30. # a lock for a thread-safe go()
  31. go_lock = thread.allocate_lock()
  32.  
  33. def go(stop=0):
  34.     # run the highest-priority profiler in 'profilers'
  35.     global current
  36.     go_lock.acquire()
  37.     try:
  38.         prev = current
  39.         if stop:
  40.             del profilers[:]
  41.         if prev:
  42.             if profilers and profilers[0] is prev:
  43.                 return    # best profiler already running
  44.             prev.stop()
  45.             current = None
  46.         for p in profilers[:]:
  47.             if p.start():
  48.                 current = p
  49.                 if logger: # and p is not prev:
  50.                     logger.write("%s: starting" % p.__class__.__name__, 5)
  51.                 return
  52.     finally:
  53.         go_lock.release()
  54.     # no profiler is running now
  55.     if stop:
  56.         if logger:
  57.             logger.writefinalstats()
  58.     else:
  59.         tag2bind()
  60.  
  61. atexit.register(go, 1)
  62.  
  63.  
  64. def buildfncache(globals, cache):
  65.     if hasattr(types.IntType, '__dict__'):
  66.         clstypes = (types.ClassType, types.TypeType)
  67.     else:
  68.         clstypes = types.ClassType
  69.     for x in globals.values():
  70.         if isinstance(x, types.MethodType):
  71.             x = x.im_func
  72.         if isinstance(x, types.FunctionType):
  73.             cache[x.func_code] = x, ''
  74.         elif isinstance(x, clstypes):
  75.             for y in x.__dict__.values():
  76.                 if isinstance(y, types.MethodType):
  77.                     y = y.im_func
  78.                 if isinstance(y, types.FunctionType):
  79.                     cache[y.func_code] = y, x.__name__
  80.  
  81. # code-to-function mapping (cache)
  82. function_cache = {}
  83.  
  84. def trytobind(co, globals, log=1):
  85.     try:
  86.         f, clsname = function_cache[co]
  87.     except KeyError:
  88.         buildfncache(globals, function_cache)
  89.         try:
  90.             f, clsname = function_cache[co]
  91.         except KeyError:
  92.             if logger:
  93.                 logger.write('warning: cannot find function %s in %s' %
  94.                              (co.co_name, globals.get('__name__', '?')), 3)
  95.             return  # give up
  96.     if logger and log:
  97.         modulename = globals.get('__name__', '?')
  98.         if clsname:
  99.             modulename += '.' + clsname
  100.         logger.write('bind function: %s.%s' % (modulename, co.co_name), 1)
  101.     f.func_code = _psyco.proxycode(f)
  102.  
  103.  
  104. if PYTHON_SUPPORT:
  105.     # the list of code objects that have been tagged
  106.     tagged_codes = []
  107.     
  108.     def tag(co, globals):
  109.         if logger:
  110.             try:
  111.                 f, clsname = function_cache[co]
  112.             except KeyError:
  113.                 buildfncache(globals, function_cache)
  114.                 try:
  115.                     f, clsname = function_cache[co]
  116.                 except KeyError:
  117.                     clsname = ''  # give up
  118.             modulename = globals.get('__name__', '?')
  119.             if clsname:
  120.                 modulename += '.' + clsname
  121.             logger.write('tag function: %s.%s' % (modulename, co.co_name), 1)
  122.         tagged_codes.append((co, globals))
  123.         _psyco.turbo_frame(co)
  124.         _psyco.turbo_code(co)
  125.  
  126.     def tag2bind():
  127.         if tagged_codes:
  128.             if logger:
  129.                 logger.write('profiling stopped, binding %d functions' %
  130.                              len(tagged_codes), 2)
  131.             for co, globals in tagged_codes:
  132.                 trytobind(co, globals, 0)
  133.             function_cache.clear()
  134.             del tagged_codes[:]
  135.  
  136. else:
  137.     # tagging is impossible, always bind
  138.     tag = trytobind
  139.     def tag2bind():
  140.         pass
  141.  
  142.  
  143.  
  144. class Profiler:
  145.     MemoryTimerResolution = 0.103
  146.  
  147.     def run(self, memory, time, memorymax, timemax):
  148.         self.memory = memory
  149.         self.memorymax = memorymax
  150.         self.time = time
  151.         if timemax is None:
  152.             self.endtime = None
  153.         else:
  154.             self.endtime = time.time() + timemax
  155.         self.alarms = []
  156.         profilers.append(self)
  157.         go()
  158.     
  159.     def start(self):
  160.         curmem = _psyco.memory()
  161.         memlimits = []
  162.         if self.memorymax is not None:
  163.             if curmem >= self.memorymax:
  164.                 if logger:
  165.                     logger.writememory()
  166.                 return self.limitreached('memorymax')
  167.             memlimits.append(self.memorymax)
  168.         if self.memory is not None:
  169.             if self.memory <= 0:
  170.                 if logger:
  171.                     logger.writememory()
  172.                 return self.limitreached('memory')
  173.             memlimits.append(curmem + self.memory)
  174.             self.memory_at_start = curmem
  175.  
  176.         curtime = time.time()
  177.         timelimits = []
  178.         if self.endtime is not None:
  179.             if curtime >= self.endtime:
  180.                 return self.limitreached('timemax')
  181.             timelimits.append(self.endtime - curtime)
  182.         if self.time is not None:
  183.             if self.time <= 0.0:
  184.                 return self.limitreached('time')
  185.             timelimits.append(self.time)
  186.             self.time_at_start = curtime
  187.         
  188.         try:
  189.             self.do_start()
  190.         except error, e:
  191.             if logger:
  192.                 logger.write('%s: disabled by psyco.error:' % (
  193.                     self.__class__.__name__), 4)
  194.                 logger.write('    %s' % str(e), 3)
  195.             return 0
  196.         
  197.         if memlimits:
  198.             self.memlimits_args = (time.sleep, (self.MemoryTimerResolution,),
  199.                                    self.check_memory, (min(memlimits),))
  200.             self.alarms.append(_psyco.alarm(*self.memlimits_args))
  201.         if timelimits:
  202.             self.alarms.append(_psyco.alarm(time.sleep, (min(timelimits),),
  203.                                             self.time_out))
  204.         return 1
  205.     
  206.     def stop(self):
  207.         for alarm in self.alarms:
  208.             alarm.stop(0)
  209.         for alarm in self.alarms:
  210.             alarm.stop(1)   # wait for parallel threads to stop
  211.         del self.alarms[:]
  212.         if self.time is not None:
  213.             self.time -= time.time() - self.time_at_start
  214.         if self.memory is not None:
  215.             self.memory -= _psyco.memory() - self.memory_at_start
  216.  
  217.         try:
  218.             self.do_stop()
  219.         except error:
  220.             return 0
  221.         return 1
  222.  
  223.     def check_memory(self, limit):
  224.         if _psyco.memory() < limit:
  225.             return self.memlimits_args
  226.         go()
  227.  
  228.     def time_out(self):
  229.         self.time = 0.0
  230.         go()
  231.  
  232.     def limitreached(self, limitname):
  233.         try:
  234.             profilers.remove(self)
  235.         except ValueError:
  236.             pass
  237.         if logger:
  238.             logger.write('%s: disabled (%s limit reached)' % (
  239.                 self.__class__.__name__, limitname), 4)
  240.         return 0
  241.  
  242.  
  243. class FullCompiler(Profiler):
  244.  
  245.     def do_start(self):
  246.         _psyco.profiling('f')
  247.  
  248.     def do_stop(self):
  249.         _psyco.profiling('.')
  250.  
  251.  
  252. class RunOnly(Profiler):
  253.  
  254.     def do_start(self):
  255.         _psyco.profiling('n')
  256.  
  257.     def do_stop(self):
  258.         _psyco.profiling('.')
  259.  
  260.  
  261. class ChargeProfiler(Profiler):
  262.  
  263.     def __init__(self, watermark, parentframe):
  264.         self.watermark = watermark
  265.         self.parent2 = parentframe * 2.0
  266.         self.lock = thread.allocate_lock()
  267.  
  268.     def init_charges(self):
  269.         _psyco.statwrite(watermark = self.watermark,
  270.                          parent2   = self.parent2)
  271.  
  272.     def do_stop(self):
  273.         _psyco.profiling('.')
  274.         _psyco.statwrite(callback = None)
  275.  
  276.  
  277. class ActiveProfiler(ChargeProfiler):
  278.  
  279.     def active_start(self):
  280.         _psyco.profiling('p')
  281.  
  282.     def do_start(self):
  283.         self.init_charges()
  284.         self.active_start()
  285.         _psyco.statwrite(callback = self.charge_callback)
  286.  
  287.     def charge_callback(self, frame, charge):
  288.         tag(frame.f_code, frame.f_globals)
  289.  
  290.  
  291. class PassiveProfiler(ChargeProfiler):
  292.  
  293.     initial_charge_unit   = _psyco.statread('unit')
  294.     reset_stats_after     = 120      # half-lives (maximum 200!)
  295.     reset_limit           = initial_charge_unit * (2.0 ** reset_stats_after)
  296.  
  297.     def __init__(self, watermark, halflife, pollfreq, parentframe):
  298.         ChargeProfiler.__init__(self, watermark, parentframe)
  299.         self.pollfreq = pollfreq
  300.         # self.progress is slightly more than 1.0, and computed so that
  301.         # do_profile() will double the change_unit every 'halflife' seconds.
  302.         self.progress = 2.0 ** (1.0 / (halflife * pollfreq))
  303.  
  304.     def reset(self):
  305.         _psyco.statwrite(unit = self.initial_charge_unit, callback = None)
  306.         _psyco.statreset()
  307.         if logger:
  308.             logger.write("%s: resetting stats" % self.__class__.__name__, 1)
  309.  
  310.     def passive_start(self):
  311.         self.passivealarm_args = (time.sleep, (1.0 / self.pollfreq,),
  312.                                   self.do_profile)
  313.         self.alarms.append(_psyco.alarm(*self.passivealarm_args))
  314.  
  315.     def do_start(self):
  316.         tag2bind()
  317.         self.init_charges()
  318.         self.passive_start()
  319.  
  320.     def do_profile(self):
  321.         _psyco.statcollect()
  322.         if logger:
  323.             logger.dumpcharges()
  324.         nunit = _psyco.statread('unit') * self.progress
  325.         if nunit > self.reset_limit:
  326.             self.reset()
  327.         else:
  328.             _psyco.statwrite(unit = nunit, callback = self.charge_callback)
  329.         return self.passivealarm_args
  330.  
  331.     def charge_callback(self, frame, charge):
  332.         trytobind(frame.f_code, frame.f_globals)
  333.  
  334.  
  335. class ActivePassiveProfiler(PassiveProfiler, ActiveProfiler):
  336.  
  337.     def do_start(self):
  338.         self.init_charges()
  339.         self.active_start()
  340.         self.passive_start()
  341.  
  342.     def charge_callback(self, frame, charge):
  343.         tag(frame.f_code, frame.f_globals)
  344.  
  345.  
  346.  
  347. #
  348. # we register our own version of sys.settrace(), sys.setprofile()
  349. # and thread.start_new_thread().
  350. #
  351.  
  352. def psyco_settrace(*args, **kw):
  353.     "This is the Psyco-aware version of sys.settrace()."
  354.     result = original_settrace(*args, **kw)
  355.     go()
  356.     return result
  357.  
  358. def psyco_setprofile(*args, **kw):
  359.     "This is the Psyco-aware version of sys.setprofile()."
  360.     result = original_setprofile(*args, **kw)
  361.     go()
  362.     return result
  363.  
  364. def psyco_thread_stub(callable, args, kw):
  365.     _psyco.statcollect()
  366.     if kw is None:
  367.         return callable(*args)
  368.     else:
  369.         return callable(*args, **kw)
  370.  
  371. def psyco_start_new_thread(callable, args, kw=None):
  372.     "This is the Psyco-aware version of thread.start_new_thread()."
  373.     return original_start_new_thread(psyco_thread_stub, (callable, args, kw))
  374.  
  375. original_settrace         = sys.settrace
  376. original_setprofile       = sys.setprofile
  377. original_start_new_thread = thread.start_new_thread
  378. sys.settrace            = psyco_settrace
  379. sys.setprofile          = psyco_setprofile
  380. if PYTHON_SUPPORT:
  381.     thread.start_new_thread = psyco_start_new_thread
  382.     # hack to patch threading._start_new_thread if the module is
  383.     # already loaded
  384.     if (sys.modules.has_key('threading') and
  385.         hasattr(sys.modules['threading'], '_start_new_thread')):
  386.         sys.modules['threading']._start_new_thread = psyco_start_new_thread
  387.